/*
 * Copyright (c) 2021. Moses All Right Reserved
 */

package com.moses.inner_class;

/**
 * @author Moses
 * @email shenhuohui@gmail.com
 * @date 2021/5/20 22:37
 */
public class Out {
    private static  int outStaticProp1;
    private int outProp1;

    Out(){
        System.out.println("Out Created");
    }

    private void outMethod(){
        // 外部类可以直接访问静态内部类的变量，不管是否静态，是否私有
        StaticInner.staticStaticProp1 = 1;
        new StaticInner().staticInnerProp1 = 1;
        // 外部类的非静态方法，可以直接实例化内部类并操作它的私有非静态变量
        new Inner().innerProp2 = 1;
    }

    private static void outMethod2(){
        // 外部类的静态方法没有外部类的 this指向，不能只能实例化内部类
        // new Inner().innerProp2 = 1;
        // 只能依赖外部对象，先实例化外部对象，再实例化内部类
        new Out().new Inner().innerProp2 = 1;
    }

    // 非静态内部类
    // 可以用权限修饰符修饰，跟成员变量一样
    class Inner{

        // 非静态内部类不可有静态代码块
        // static {
        //
        // }
        // 非静态内部类不可有静态变量
        // static int innerProp1;

        // 但可以有静态常量
        final static int finalProp1 = 1;
        int innerProp2;

        Inner(){
            System.out.println("Inner Created");
        }

        // 非静态内部类不可有静态方法
        // 因为静态变量和方法在类加载时就会加载到内存中，
        // 而非静态内部类的实例依赖外部类，外部类又没有实例化，无法加载到内存中
        // static void method2(){
        //
        // }

        void setOutStaticProp1(int a){
            // 可以访问外部类成员变量，不管是否私有，是否静态
            outStaticProp1 = a;
            outProp1 = a;
            // 也可以访问外部类的方法，不管是否私有，是否静态
            outMethod();
            outMethod2();

            // 所有对外部的操作像对自己操作一样，或者说像外部类操作自己一样
        }
    }

    // 静态内部类
    static class StaticInner{

        static  int  staticStaticProp1;
        private int staticInnerProp1;

        StaticInner(){
            System.out.println("StaticInner Created");
        }

        // 静态内部类可以有静态和非静态方法
        static void method(){

        }

        void setOutStaticProp1(int a){
            // 只能操作外部类的静态变量，不是是否私有
            outStaticProp1 = a;
            // 静态内部类不能访问外部类的非静态成员
            // outProp1 = a;
            // 只能操作外部类的静态方法，不是是否私有
            outMethod2();

            // 静态内部类只能操作外部类的静态变量及方法，非静态不可访问
        }

    }

    // 局部内部类
    public  void partInnerClass(final int d){
        int c = 7;

        // 局部内部类定义在外部类的方法中
        class PartInnerClass{
            private int partInnerProp1 = 2;

            void part(){
                System.out.println(c);
            }

            void part2(){
                System.out.println(d);
            }
        }
        PartInnerClass pc = new PartInnerClass();

        // 此处会出现数据不一致性问题
        // 因为a与线程的生命周期不一致，可能a的生命周期已经结束，但线程还为结束
        // 因此 java 使用“复制”解决生命周期不一致的问题，把a复制给线程内部，操作的另外一个与a等值的变量
        // 因此最好的编码方式是：final int a = 10;如果是引用，限定引用不可变更
        // JDK8后，编译器会默认添加 final
        int a = 10;
        new Thread(() -> System.out.println(a)).start();
    }

    // 可以通过外部类方法获得非静态内部类实例
    public Inner getInner(){
        return new Inner();
    }

    // 可以通过外部类方法获得静态内部类实例
    public StaticInner getStaticInner(){
        return new StaticInner();
    }

}
